﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ObservadorPeplau.API;
using ObservadorPeplau.API.Business;

namespace ObservadorPeplau.Usercontrols
{
    public partial class DiscussionGrid : UserControl
    {
        private bool _isOverAStar;
        
        public delegate void GridClick(DiscussionGrid grid, Discussion selected);
        public GridClick DoubleClickEventHandler { get; set; }
        public GridClick ClickEventHandler { get; set; }
        public GridClick StarClickEventHandler { get; set; }

        public List<Discussion> Discussions { get; set; }

        public View GridViewType
        {
            get { return lsvGrid.View; }
            set { lsvGrid.View = value; }
        }

        public DiscussionGrid()
        {
            InitializeComponent();
            Bind();
        }

        private void DiscussionListGrid_Load(object sender, EventArgs e)
        {
        }

        public void Bind()
        {
            AdjustColumnSizes();

            if (Discussions == null)
                return;

            lsvGrid.Items.Clear();
            foreach (var objDiscussion in Discussions)
                lsvGrid.Items.Add(NewListViewItemFromDiscussion(objDiscussion));

            AdjustColumnSizes();
        }

        private ListViewItem NewListViewItemFromDiscussion(Discussion discussion)
        {
            return new ListViewItem
                       {
                           Name = discussion.Url,
                           Font = new Font(Font.Name, Font.Size, !discussion.IsRead ? FontStyle.Bold : FontStyle.Regular),
                           Tag = discussion.Url,
                           Text = discussion.Title,
                           ImageIndex = (discussion.IsStared) ? 1 : 0,
                           SubItems =
                               {
                                   discussion.Author.Login,
                                   discussion.NumberOfComments.ToString()
                               },
                       };
        }

        public List<Discussion> GetSelectedDiscussions()
        {
            return GetSelectedDiscussions(Discussions);
        }

        public List<Discussion> GetSelectedDiscussions(List<Discussion> lstContext)
        {
            var lstRet = new List<Discussion>();
            if (lsvGrid.SelectedItems.Count == 0)
                return lstRet;

            lstRet.AddRange(from ListViewItem selectedItem in lsvGrid.SelectedItems select Discussions.First(p => p.Url == selectedItem.Tag.ToString()));

            return lstRet;
        }

        private ListViewItem GetListViewItemFromDiscussion(Discussion discussion)
        {
            var lstAllItems = lsvGrid.Items.Cast<ListViewItem>();
            return lstAllItems.First(p => p.Tag.ToString() == discussion.Url);            
        }

        public void Syncronize(Discussion discussion)
        {
            // New Discussion - Insert at the begginin of the list
            if (Discussions.Count(p => p.Url == discussion.Url) == 0)
            {
                Discussions.Insert(0, discussion);
                lsvGrid.Items.Insert(0, NewListViewItemFromDiscussion(discussion));
                return;
            }

            // Get current stared item status from the grid
            bool isStaredOnGrid = lsvGrid.Items[discussion.Url].ImageIndex == 1;
            bool isReadOnGrid = !lsvGrid.Items[discussion.Url].Font.Bold;

            // Exists in the grid, but with different data
            // Existent Discussion - Update the row
            if (
                (discussion.IsStared && !discussion.IsRead)
                || Discussions.Count(
                        p => p.Url == discussion.Url
                            && (
                                p.Title != discussion.Title
                                || p.NumberOfComments != discussion.NumberOfComments
                                || p.IsStared != isStaredOnGrid
                                || p.IsRead != isReadOnGrid
                            )
                ) > 0
            )
            {
                var index = Discussions.IndexOf(Discussions.First(p => p.Url == discussion.Url));
                Discussions.RemoveAt(index);
                Discussions.Insert(index, discussion);

                lsvGrid.Items.RemoveByKey(discussion.Url);
                lsvGrid.Items.Insert(index, NewListViewItemFromDiscussion(discussion));
            }            
        }

        public void Syncronize(List<Discussion> lstDiscussions)
        {
            if (Discussions == null)
            {
                Discussions = lstDiscussions;
                return;
            }

            // Add / Update Discussions
            foreach (var newDiscussion in lstDiscussions)
                Syncronize(newDiscussion);

            // Delete Discussions that doesn't exists anymore
            var tempList = new List<Discussion>(Discussions);
            foreach (var discussion in tempList)
                if (lstDiscussions.Count(p=>p.Url==discussion.Url)==0)
                    Delete(discussion);
        }

        public void Delete(Discussion discussion)
        {
            Discussions.Remove(discussion);
            lsvGrid.Items.RemoveByKey(discussion.Url);
        }

        public void AddDiscussion(Discussion discussion)
        {
            var newList = new List<Discussion>(Discussions);
            newList.Insert(0, discussion);
            Syncronize(newList);
        }

        public void RemoveDiscussion(Discussion discussion)
        {
            if (Discussions.Count(p => p.Url == discussion.Url) == 0)
                return;

            var newList = new List<Discussion>(Discussions);
            var existentDiscussion = Discussions.First(p => p.Url == discussion.Url);
            newList.Remove(existentDiscussion);

            Syncronize(newList);            
        }

        private void AdjustColumnSizes()
        {
            // Set all columns to the width of their contents
            lsvGrid.Columns[0].Width = 1;
            for (int i = 1; i < lsvGrid.Columns.Count; i++)
                lsvGrid.Columns[i].Width = -1;

            // Get sum of widths of all columns except the first
            var columnWidths = 0;
            for (int i = 1; i < lsvGrid.Columns.Count; i++)
                columnWidths += lsvGrid.Columns[i].Width;

            // Set first column with the width that remains
            lsvGrid.Columns[0].Width = lsvGrid.ClientSize.Width - columnWidths;
        }

        private void AdjustTileSize()
        {
            lsvGrid.TileSize = new Size(lsvGrid.ClientSize.Width,imlLargeStars.ImageSize.Height);
        }

        private void DiscussionListGrid_Resize(object sender, EventArgs e)
        {
        }
        private void lsvGrid_ClientSizeChanged(object sender, EventArgs e)
        {
            AdjustColumnSizes();
            AdjustTileSize();
        }

        private void lstGrid_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (DoubleClickEventHandler != null)
            {
                var selectedDiscussions = GetSelectedDiscussions();
                DoubleClickEventHandler(this, selectedDiscussions.Count == 0 ? null : selectedDiscussions[0]);
            }            
        }

        private void lsvGrid_MouseClick(object sender, MouseEventArgs e)
        {
            var selectedDiscussions = GetSelectedDiscussions();
            if (_isOverAStar && selectedDiscussions.Count > 0)
            {
                // Set discussion as stared/unstared
                var selectedDiscussion = selectedDiscussions[0];
                var selectedListItem = GetListViewItemFromDiscussion(selectedDiscussion);

                selectedDiscussion.IsStared = !selectedDiscussion.IsStared;
                selectedListItem.ImageIndex = selectedDiscussion.IsStared ? 1 : 0;

                // Call External Star event handler
                if (StarClickEventHandler != null)
                    StarClickEventHandler(this, selectedDiscussions.Count == 0 ? null : selectedDiscussions[0]);
            }

            if (ClickEventHandler != null)
                ClickEventHandler(this, selectedDiscussions.Count == 0 ? null : selectedDiscussions[0]);
        }

        private void lsvGrid_MouseMove(object sender, MouseEventArgs e)
        {
            var cursorPositionX = Cursor.Position.X;
            var cursorPositionY = Cursor.Position.Y;
            var gridLeft = lsvGrid.PointToScreen(new Point(0, 0)).X + lsvGrid.Margin.Left;
            var imageWidth = (lsvGrid.View == View.LargeIcon || lsvGrid.View == View.Tile)
                                 ? imlLargeStars.ImageSize.Width
                                 : imlSmallStars.ImageSize.Width;

            // Min and Max X
            var minX = gridLeft;
            var maxX = minX + imageWidth + lsvGrid.Margin.Left;

            // Determine if is over a star
            _isOverAStar = (cursorPositionX >= minX && cursorPositionX <= maxX);

            // Change cursor accordingly
            lsvGrid.Cursor = _isOverAStar ? lsvGrid.Cursor = Cursors.Hand : lsvGrid.Cursor = Cursors.Default;
        }

        private void lsvGrid_ItemMouseHover(object sender, ListViewItemMouseHoverEventArgs e)
        {
        }

        private void lsvGrid_MouseLeave(object sender, EventArgs e)
        {
        }

        private void rightClickMenu_Opening(object sender, CancelEventArgs e)
        {
            var selectedDiscussions = GetSelectedDiscussions();
            if (selectedDiscussions.Count == 0)
            {
                e.Cancel = true;
                return;
            }

            e.Cancel = false;
            rightClickMenu.Items.Clear();

            if (selectedDiscussions.Count==1)
                rightClickMenu.Items.Add(selectedDiscussions[0].IsRead ? Constants.MarkAsUnread : Constants.MarkAsRead);
            else
            {
                if (selectedDiscussions.Count(p => !p.IsRead) > 0)
                    rightClickMenu.Items.Add(Constants.MarkSelectedAsRead);
                if (selectedDiscussions.Count(p => p.IsRead) > 0)
                    rightClickMenu.Items.Add(Constants.MarkSelectedAsUnread);
            }
        }

        private void rightClickMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            var newList = new List<Discussion>(Discussions);
            var selectedDiscussions = GetSelectedDiscussions(newList);
            if (selectedDiscussions.Count == 1)
            {
                var selectedDiscussion = selectedDiscussions[0];
                selectedDiscussion.IsRead = (e.ClickedItem.Text == Constants.MarkAsRead);
            }
            else if (selectedDiscussions.Count>1)
            {
                var isRead = (e.ClickedItem.Text == Constants.MarkSelectedAsRead);
                foreach (var discussion in selectedDiscussions)
                {
                    discussion.IsRead = isRead;
                }
            }

            Syncronize(newList);
        }
    }
}
